﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
using System.Net;
using WTwitter.Model.UserData;
using WTwitter.Model.Twitter;
using WTwitter.Model.Framework;
using WTwitter.Model.SearchTwitter;
using WTwitter.Model.Twitter.Json;
using WTwitter.View;
using WTwitter.Model.Filters;
using WTwitter.ViewModel.Utility;
using System.ComponentModel;
using System.Windows.Input;
using System.Windows.Media.Imaging;
using System.Windows.Data;

namespace WTwitter.ViewModel {
	sealed public class MainWindowViewModel : ClosableViewModelBase {
		#region private member
		private Option _option;
		private AuthInfo _userInfo;
		private ObservableCollection<ImageButton> _commandButtons = new ObservableCollection<ImageButton>();
		private MultiSourceTimeline _allItemTimeline;
		private List<Filter> _commonFilter;
		private ObservableCollection<TimelineViewModel> _timelines = new ObservableCollection<TimelineViewModel>();
		private CollectionViewSource _TimelinesViewSource;
		private StatusBarViewModel _statusbar;
		#endregion

		public MainWindowViewModel(Option option) :
			base(string.Format("{0} version {1}",AppInfo.AppName, AppInfo.Version)) {
			_option = option;
			_userInfo = option.UserInfo;
			_allItemTimeline = new MultiSourceTimeline(_userInfo);
			 _statusbar = new StatusBarViewModel(this);
			_TimelinesViewSource = new CollectionViewSource();
			_TimelinesViewSource.Source = _timelines;
		}

		#region Commands
		private RelayCommand _closeCommand;
		public ICommand CloseCommand {
			get {
				return _closeCommand = _closeCommand ?? new RelayCommand(param => Close());
			}
		}

		private RelayCommand _optionDialogCommmand;
		/// <summary>
		/// オプションダイアログを開く
		/// </summary>
		public ICommand OptionDialogCommand {
			get {
				if (_optionDialogCommmand == null) {
					_optionDialogCommmand = new RelayCommand(this.OpenOptionDialog);
				}
				return _optionDialogCommmand;
			}
		}

		public void OpenOptionDialog(object parameter) {
			var vm = new OptionViewModel(_option);
			var dialog = new OptionDialog(vm);
			var result = dialog.ShowDialog();

			if (result == true) {
				//TODO変更があったら呼び出すようにすべき
				//変更をどのように検出するかがT.B.D.
				if (_option.UserInfo.AuthState != AuthState.Verified) {
					OnAuthInfoChanged();
				}

				//削除されたタイムラインを検出
				var timelineToDel = (from timeline in this.Timelines
						  where (!_option.TimelineSettings.Any(setting => setting.Name == timeline.DisplayName)
							&& timeline.DisplayName != "All")
						  select timeline).ToList<TimelineViewModel>();
				foreach (var timeline in timelineToDel) {
					Timelines.Remove(timeline);
				}

				//新しく追加されたタイムライン設定を検出
				var settingToAdd = (from setting in _option.TimelineSettings
									where !this.Timelines.Any(timeline => timeline.DisplayName == setting.Name)
									select setting).ToList<TimelineSetting>();
				foreach (var setting in settingToAdd) {
					OnNewTimelineSettingAdded(setting);
				}

				//残りのタイムラインを更新する
				var otherTimelines = (from timeline in this.Timelines
								 where !settingToAdd.Any(item => item.Name == timeline.DisplayName)
								 select timeline).ToList<TimelineViewModel>();

				foreach (var timeline in otherTimelines) {
					timeline.Reload();
					if (timeline.IsUpdatable && !timeline.IsAutoUpdating) {
						timeline.Update();
						timeline.StartAutoUpdate();
					}
				}
			}
		}

		private RelayCommand _showSubmitPanelCommand;

		/// <summary>
		/// 投稿欄を表示する
		/// </summary>
		public ICommand ShowSubmitPanelCommand {
			get {
				if (_showSubmitPanelCommand == null) {
					_showSubmitPanelCommand = new RelayCommand(this.ShowSubmitPanel);
				}
				return _showSubmitPanelCommand;
			}
		}

		private void ShowSubmitPanel(object parameter) {
			var vm = new SubmitPanelViewModel(_userInfo);
			Utility.ViewConnector.Instance.Show(vm);
		}

		#endregion

		#region Public Method
		/// <summary>
		/// 
		/// </summary>
		/// <returns>初期化が問題なく成功したかどうか</returns>
		public bool Initialize() {
			////Modelの作成

			//ツールバーのボタンの作成
			var baseUri = System.IO.Directory.GetParent(
				System.Reflection.Assembly.GetExecutingAssembly().Location).FullName;
			var commands = new ImageButton[] {
				new ImageButton("投稿", ShowSubmitPanelCommand,
				    App.Current.FindResource("SubmitImage") as BitmapImage),
				new ImageButton("設定", OptionDialogCommand,
				    App.Current.FindResource("SettingImage") as BitmapImage),
			};

			foreach (var comm in commands) {
				_commandButtons.Add(comm);
			}

			_commonFilter = CreateFrom(_option.Filters);

			var isSuccess = false;
			var tryCount = 0;
			//認証に最大５回トライする
			do {
				isSuccess = true;
				try {
					OnAuthInfoChanged();
				} catch (WebException) {
					isSuccess = false;
					System.Threading.Thread.Sleep(100);
				}
			} while(!isSuccess && tryCount++ < 5);

			if (!isSuccess) return false;

			//Modelの作成
			var allVM = TimelineViewModel.GetAllTimelineViewModel("All", _option.UserInfo, _allItemTimeline, Enumerable.Empty<TimelineItemViewModel>(), _commonFilter);
			Timelines.Add(allVM);
			foreach (var setting in _option.TimelineSettings) {
				OnNewTimelineSettingAdded(setting);
			}
			return true;
		}

		private void OnAuthInfoChanged() {
			if (_option.UserInfo.VerifyCredential()) {
				var user = _option.UserInfo.User as TwitterUser;
				user.LoadFollowersIds(_option.UserInfo);
				user.LoadFollowingIds(_option.UserInfo);
			}
		}

		private void OnNewTimelineSettingAdded(TimelineSetting setting) {
			var vm = CreateFrom(setting, _commonFilter);
			vm.AllItems.CollectionChanged += (sender, e) => {
				if (e.NewItems != null && e.NewItems.Count > 0) {
					foreach (var item in e.NewItems) {
						TimelineItemVMCache.Instance.Add(item as TimelineItemViewModel);
					}
				}
			};
			Timelines.Add(vm);
			if (vm.IsUpdatable) {
				vm.Update();
				vm.StartAutoUpdate();
			}
		}
		#endregion

		#region private method
		/// <summary>
		/// settingファイルの情報からViewModelを作成する
		/// </summary>
		/// <param name="setting"></param>
		/// <returns></returns>
		private TimelineViewModel CreateFrom(TimelineSetting setting, List<Filter> filters) {
			IItemsReader reader;
			Timeline timeline;

			switch (setting.TimelineType) {
				case TimelineSetting.Type.Normal:
					reader = new TwitterItemsReader();
					timeline = new TwitterTimeline(setting, reader, _userInfo);
					break;
				case TimelineSetting.Type.DirectMessage:
					reader = new DirectMessageReader();
					timeline = new TwitterTimeline(setting, reader, _userInfo);
					break;
				case TimelineSetting.Type.Search:
					reader = new SearchTwitterItemsReader();
					timeline = new Timeline(setting, reader, _userInfo);
					break;
				default:
					throw new Exception("Settingのフォーマットが正しくありません");
			}
			_allItemTimeline.AddTimeline(timeline);
			var vm = new TimelineViewModel(setting, _userInfo, timeline, filters);
			return vm;
		}

		/// <summary>
		/// オプション設定から実際にフィルタを作る
		/// </summary>
		/// <param name="settings"></param>
		/// <returns>設定から読み出した全フィルタリスト</returns>
		private List<Filter> CreateFrom(IEnumerable<FilterSetting> settings) {
			var list = new List<Filter>();
			foreach (var setting in settings) {
				switch (setting.Target) {
					case FilterTargetType.Id:
						foreach (var word in setting.ngList) {
							NgFilterById.Common.AddNg(word);
						}
						break;
					case FilterTargetType.Text:
						throw new NotImplementedException();
					default:
						//とりあえず何もしない
						break;
				}
			}
			list.Add(NgFilterById.Common);
			return list;
		}
		#endregion

		#region Property
		/// <summary>
		/// MainViewに表示するすべてのタイムライン
		/// </summary>
		public ObservableCollection<TimelineViewModel> Timelines {
			get { return _timelines; }
		}

		/// <summary>
		/// コマンド用のイメージ付きボタン
		/// </summary>
		public ObservableCollection<ImageButton> CommandButtons {
			get { return _commandButtons; }
		}

		public StatusBarViewModel StatusBar {
			get { return _statusbar; }
		}

		public CollectionViewSource TimelinesViewSource {
			get {
				return _TimelinesViewSource;
			}
		}
		#endregion
	}
}
